#ifndef __OSAPICC12_H__
#define __OSAPICC12_H__


#undef OS_SMSG_SIZE
#define OS_SMSG_SIZE    sizeof(OST_SMSG)
    
    
asm("   psect os_pic12_jmp_table,ovrld,global,class=ENTRY,delta=2   ");
asm("_os_pic12_jmp_table:                                           ");


//______________________________________________________________________________
//******************************************************************************

static volatile char _indf @ 0x0;
static volatile char _pcl @ 0x02;
static volatile char _fsr @ 0x4;
static volatile char _status @ 0x3;

#define _FSR_TYPE            unsigned char
#define _PIC18_ERRATA_NOP()     // Empty macro for this type of PICs 


//------------------------------------------------------------------------------



// Code pointer type (used in TCB)
#define OST_CODE_POINTER    unsigned char


#define OST_TASK_POINTER   OS_TASKS_BANK OST_TCB * 



#define OS_CLRWDT()   asm(" clrwdt ");
#define OS_ClrWdt()   asm(" clrwdt ");
#define OS_SLEEP()    asm(" sleep  ");




#if defined(OS_ENABLE_QMSG) || defined(OS_ENABLE_QSMSG)
    #define OS_ENABLE_QMSG
    #undef  OS_ENABLE_QSMSG
    #define OS_QMSG_QSMSG_IDENTICAL
#endif


//______________________________________________________________________________
/******************************************************************************
 * Switch control routines:
 *
 *  _OS_JumpToTask() - jump indirectly from kernel (OS_Sched) into task
 *  _OS_SaveRetAddr() - task return to this point 
 *
 *  _OS_GetReturnPoint() - exit from task and save context
 *  _OS_CallGetReturnPoint() - save context without exiting task
 *  _OS_ReturnNoSave() - exit task without saving context
 *
 *******************************************************************************/


    
#if !defined(_BANKBITS_)
#define _BANKBITS_  2
#endif


//------------------------------------------------------------------------------
#if     OS_BANK_TASKS == 0
    #define _OS_SET_TASK_IRP()
    #define _OS_SET_TASK_IRP_0()
#elif   OS_BANK_TASKS == 1
    #define _OS_SET_TASK_IRP()      asm("   bsf     __fsr, 5 ");
    #define _OS_SET_TASK_IRP_0()    asm("   bcf     __fsr, 5 ");
#elif   OS_BANK_TASKS == 2
    #define _OS_SET_TASK_IRP()      asm("   bsf     __fsr, 6 ");
    #define _OS_SET_TASK_IRP_0()    asm("   bcf     __fsr, 6 ");
#elif   OS_BANK_TASKS == 3
    #define _OS_SET_TASK_IRP()      asm("   bsf     __fsr, 5 ");    \
                                    asm("   bsf     __fsr, 6 ");
    #define _OS_SET_TASK_IRP_0()    asm("   bcf     __fsr, 5 ");    \
                                    asm("   bcf     __fsr, 6 ");
#endif
//------------------------------------------------------------------------------
#if     OS_BANK_OS == 0
    #define _OS_SET_OS_IRP()
    #define _OS_SET_OS_IRP_0()
#elif   OS_BANK_OS == 1
    #define _OS_SET_OS_IRP()    asm("   bsf     __fsr, 5 ");
    #define _OS_SET_OS_IRP_0()  asm("   bcf     __fsr, 5 ");
#elif   OS_BANK_OS == 2
    #define _OS_SET_OS_IRP()    asm("   bsf     __fsr, 6 ");
    #define _OS_SET_OS_IRP_0()  asm("   bcf     __fsr, 6 ");
#elif   OS_BANK_OS == 3
    #define _OS_SET_OS_IRP()    asm("   bsf     __fsr, 5 ");    \
                                asm("   bsf     __fsr, 6 ");
    #define _OS_SET_OS_IRP_0()  asm("   bcf     __fsr, 5 ");    \
                                asm("   bcf     __fsr, 6 ");
#endif







//------------------------------------------------------------------------------
#if _BANKBITS_ == 0
    #define _OS_PIC12_AND_1F()
#endif        

//------------------------------------------------------------------------------
#if _BANKBITS_ == 1
    #define _OS_PIC12_AND_1F()  asm("   andlw   0x1F    ");
#endif        

//------------------------------------------------------------------------------
#if _BANKBITS_ == 2
    #define _OS_PIC12_AND_1F()  asm("   andlw   0x1F    ");
#endif        

        
//------------------------------------------------------------------------------



#define OS_SET_PAGE_ADDR0()                                     \
    asm("   global _os_pic12_jmp_table      ");                 \
    asm("   dw  0x4A3   | ((_os_pic12_jmp_table & 0x200)>>1)");

#define OS_SET_PAGE_ADDR1()                                     \
    asm("   global _os_pic12_jmp_table      ");                 \
    asm("   dw  0x4C3   | ((_os_pic12_jmp_table & 0x400)>>2)");


//------------------------------------------------------------------------------

#define _OS_JumpToTask()                                                    \
    {                                                                       \
        _fsr = ((_FSR_TYPE)_OS_CurTask);                                    \
        asm("   movf    __indf, w    ");                                    \
        _OS_SET_TASK_IRP_0();                                               \
        asm("   movwf   _OS_state   ");                                     \
        _fsr = ((_FSR_TYPE)_OS_CurTask) + 1;                                \
        asm("   movf    __indf, w    ");                                    \
        asm("   global  OS_JumpToTask_W    ");                              \
        asm("OS_JumpToTask_W:       ");                                     \
        asm("   clrf    __fsr       ");                                     \
        OS_SET_PAGE_ADDR0();                                                \
        OS_SET_PAGE_ADDR1();                                                \
        asm("   movwf   __pcl        ");                                    \
    }
        

//------------------------------------------------------------------------------





//------------------------------------------------------------------------------
// Save task return address
//------------------------------------------------------------------------------

#define _OS_SaveRetAddr()                                                   \
    {                                                                       \
        asm("global  OS_SchedRetPoint   ");                                 \
        asm("global  OS_SchedRetPoint3   ");                                \
        asm("global  OS_ClearReady  ");                                     \
        asm("global  OS_ClearReadySetCanContinue  ");                       \
        asm("global  OS_JumpToTask_W    ");                                 \
                                                                            \
        asm("OS_ClearReadySetCanContinue:  ");                              \
        asm("OS_ClearReady:  ");                                            \
        asm("   bcf   _OS_state, 3      ");     /* bReady = 0 */            \
        asm("   bsf   __status, 1        "); /* =1 - we need to return to task */ \
        asm("   btfss __status, 1        ");                                \
        asm("OS_SchedRetPoint:   ");                                        \
        asm("   bcf   __status, 1    ");                                    \
        /* Now FSR = 0, W = task return point */                            \
        asm("   movwf   __OS_temp     ");                                   \
        asm("   incf    __OS_CurTask, w ");                                 \
        _OS_PIC12_AND_1F();                                                 \
        asm("   movwf   __fsr    ");                                        \
        asm("   movf    __OS_temp, w");                                     \
        _OS_SET_TASK_IRP();                                                 \
        asm("   movwf   __indf   ");                                        \
        _OS_SET_TASK_IRP_0();                                               \
        asm("   btfsc   __status, 1 ");                                     \
        asm("   goto    OS_JumpToTask_W ");                                 \
        asm("OS_SchedRetPoint3:      ");                                    \
        /* Save state      */                                               \
        asm("   movf    __OS_CurTask, w");                                  \
        _OS_PIC12_AND_1F();                                                 \
        asm("   movwf   __fsr   ");                                         \
        asm("   movf    _OS_state, w");                                     \
        asm("   andlw   0x38    ");   /* bReady, bCanContinue and !!!bDelay!!! (!!! - only for PICC12) */ \
        _OS_SET_TASK_IRP();                                                 \
        asm("   bcf     __indf, 3");  /* bReady */                          \
        asm("   bcf     __indf, 4");  /* bDelay */                          \
        asm("   bcf     __indf, 5");  /* bCanContinue */                    \
        asm("   iorwf   __indf, f");                                        \
        _OS_SET_TASK_IRP_0();                                               \
    }
//------------------------------------------------------------------------------


//#define _OS_PIC12_JUMP_TABLE()                                                  \
//    asm("   psect os_pic12_jmp_table, ovrld, global, class=CONST, delta = 2  ");  \
//    asm("_os_pic12_jump_table:              ");                                 \



//------------------------------------------------------------------------------
/************************************************************************/
/* Add task address in jump table                                       */
/************************************************************************/
asm("_OS_Add_TaskAddr macro TaskAddr    ");
asm("   local   label2                  ");
asm("   movlw   low(label2)             ");
asm("   movwf   __OS_temp               ");
asm("   psect   os_pic12_jmp_table      ");
asm("label2:                            ");
asm("   ljmp    TaskAddr                ");
asm("   endm                            ");

//------------------------------------------------------------------------------
/************************************************************************/
/* Exit task and save context                                           */
/************************************************************************/
asm("_goto_OS_SchedRetPoint macro       ");
asm("   local   task_ret_point, label2  ");
asm("   dw      0xC00 | low(label2)     ");
asm("   global  OS_SchedRetPoint        ");
asm("   ljmp    OS_SchedRetPoint        ");
asm("task_ret_point:                    ");
asm("   psect   os_pic12_jmp_table      ");
asm("label2:                            ");
asm("   ljmp    task_ret_point          ");
asm("   endm                            ");

//------------------------------------------------------------------------------
/************************************************************************/
/* Exit task without saving context                                     */
/************************************************************************/
asm("_goto_OS_SchedRetPoint3 macro      ");
asm("   global  OS_SchedRetPoint3       ");
asm("   ljmp    OS_SchedRetPoint3       ");
asm("   endm                            ");

//------------------------------------------------------------------------------
/************************************************************************/
/* Save context with clearing bReady flag                               */
/************************************************************************/
asm("_call_OS_ClearReady macro          ");
asm("   local   task_ret_point, label2  ");
asm("   dw      0xC00 | low(label2)     ");
asm("   global  OS_ClearReady           ");
asm("   ljmp    OS_ClearReady           ");
asm("task_ret_point:                    ");
asm("   psect   os_pic12_jmp_table      ");
asm("label2:    ljmp    task_ret_point  ");
asm("   endm                            ");

//------------------------------------------------------------------------------
/************************************************************************/
/* Save context with clearing bReady and setting bCanContinue           */
/************************************************************************/
asm("_call_OS_ClearReadySetCanContinue macro    ");
asm("   local   task_ret_point, label2  ");
asm("   dw      0xC00 | low(label2)     ");
asm("   global  OS_ClearReadySetCanContinue     ");
asm("   ljmp    OS_ClearReadySetCanContinue     ");
asm("task_ret_point:                    ");
asm("   psect   os_pic12_jmp_table      ");
asm("label2:    ljmp    task_ret_point  ");
asm("   endm                            ");

//------------------------------------------------------------------------------



/************************************************************************/
/*                                                                      */
/************************************************************************/
#define _OS_GetReturnPoint()    \
    {                           \
        OS_state.bReady = 1;    \
        asm(" _goto_OS_SchedRetPoint ");\
    }
#define _OS_ReturnNoSave()                  asm(" _goto_OS_SchedRetPoint3 ");
#define _OS_CLEAR_READY()       \
    {                           \
        OS_state.bCanContinue = 0;  \
        asm(" _call_OS_ClearReady ");\
    }
#define _OS_CLEAR_READY_SET_CANCONTINUE()   \
    {                           \
        OS_state.bCanContinue = 1;  \
        asm(" _call_OS_ClearReadySetCanContinue ");\
    }

//------------------------------------------------------------------------------

#define _OS_SET_FSR_CUR_TASK_W()
#define _OS_SET_FSR_CUR_TASK()


//______________________________________________________________________________
/******************************************************************************************
 *
 * MACROS FOR OLD STYLE STATIC TIMERS WORK
 *
 ******************************************************************************************/

#define __OS_Timer8Work(TIMER_ID,L)                                                                             \
    {                                                                                                           \
        if ((OS_Timeouts[(TIMER_ID)>>3]&(1<<((TIMER_ID)&7)))) {                                                 \
            if (!++OS_Timers8[TIMER_ID])                                                                        \
                OS_Timeouts[(TIMER_ID)>>3]&=~(1<<((TIMER_ID)&7));                                               \
        }                                                                                                       \
    }


#define __OS_Timer16Work(TIMER_ID,L)                                                                            \
    {                                                                                                           \
        if ((OS_Timeouts[(TIMER_ID+_OS_TIMER16_POS)>>3]&(1<<((TIMER_ID+_OS_TIMER16_POS)&7))))                   \
        if (!++*((OS_TIMERS16_BANK char*)&OS_Timers16[TIMER_ID]+0)) {                                           \
            if (!++*((OS_TIMERS16_BANK char*)&OS_Timers16[TIMER_ID]+1)) {                                       \
                OS_Timeouts[(TIMER_ID+_OS_TIMER16_POS)>>3]&=~(1<<((TIMER_ID+_OS_TIMER16_POS)&7));               \
            };                                                                                                  \
        };                                                                                                      \
    }


#define __OS_Timer24Work(TIMER_ID,L)                                                                            \
    {                                                                                                           \
        if ((OS_Timeouts[(TIMER_ID+_OS_TIMER24_POS)>>3]&(1<<((TIMER_ID+_OS_TIMER24_POS)&7))))                   \
        if (!++*((OS_TIMERS24_BANK char*)&OS_Timers24[TIMER_ID]+0)) {                                           \
            if (!++*((OS_TIMERS24_BANK char*)&OS_Timers24[TIMER_ID]+1)) {                                       \
                OS_Timeouts[(TIMER_ID+_OS_TIMER24_POS)>>3]&=~(1<<((TIMER_ID+_OS_TIMER24_POS)&7));               \
            };                                                                                                  \
        };                                                                                                      \
    }



#define __OS_Timer32Work(TIMER_ID,L)                                                                            \
    {                                                                                                           \
        if ((OS_Timeouts[(TIMER_ID+_OS_TIMER32_POS)>>3]&(1<<((TIMER_ID+_OS_TIMER32_POS)&7))))                   \
        if (!++*((OS_TIMERS32_BANK char*)&OS_Timers32[TIMER_ID]+0)) {                                           \
            if (!++*((OS_TIMERS32_BANK char*)&OS_Timers32[TIMER_ID]+1)) {                                       \
                if (!++*((OS_TIMERS32_BANK char*)&OS_Timers32[TIMER_ID]+2)) {                                   \
                    if (!++*((OS_TIMERS32_BANK char*)&OS_Timers32[TIMER_ID]+3)) {                               \
                        OS_Timeouts[(TIMER_ID+_OS_TIMER32_POS)>>3]&=~(1<<((TIMER_ID+_OS_TIMER32_POS)&7));       \
                    };                                                                                          \
                };                                                                                              \
            };                                                                                                  \
        };                                                                                                      \
    }



//______________________________________________________________________________
/******************************************************************************************
 *
 * MACROS FOR WORK WITH TASK TIMERS
 *
 ******************************************************************************************/


#define ASM_OST_TCB_SIZE_CONST  asm(" ");
#define ASM_SET_BANK            asm(" ");


#if   OS_TTIMER_SIZE == 1
    #define __OS_TaskTimerWork(TASK_ID, L)                                                      \
        {                                                                                       \
            if (OS_TaskVars[TASK_ID].State.bDelay) {                                            \
                if (!++OS_TaskVars[TASK_ID].Timer)                                              \
                    OS_TaskVars[TASK_ID].State.bDelay = 0;                                      \
            }                                                                                   \
        }
#elif OS_TTIMER_SIZE == 2
    #define __OS_TaskTimerWork(TASK_ID, L)                                                      \
        {                                                                                       \
            if (OS_TaskVars[TASK_ID].State.bDelay)                                              \
            if (!++*((OS_TASKS_BANK char*)&OS_TaskVars[TASK_ID].Timer+0)) {                     \
                if (!++*((OS_TASKS_BANK char*)&OS_TaskVars[TASK_ID].Timer+1)) {                 \
                    OS_TaskVars[TASK_ID].State.bDelay = 0;                                      \
                }                                                                               \
            }                                                                                   \
        }
#elif OS_TTIMER_SIZE == 4
    #define __OS_TaskTimerWork(TASK_ID, L)                                                      \
        {                                                                                       \
            if (OS_TaskVars[TASK_ID].State.bDelay)                                              \
            if (!++*((OS_TASKS_BANK char*)&OS_TaskVars[TASK_ID].Timer+0)) {                     \
                if (!++*((OS_TASKS_BANK char*)&OS_TaskVars[TASK_ID].Timer+1)) {                 \
                    if (!++*((OS_TASKS_BANK char*)&OS_TaskVars[TASK_ID].Timer+2)) {             \
                        if (!++*((OS_TASKS_BANK char*)&OS_TaskVars[TASK_ID].Timer+3)) {         \
                            OS_TaskVars[TASK_ID].State.bDelay = 0;                              \
                        }                                                                       \
                    }                                                                           \
                }                                                                               \
            }                                                                                   \
        }

#endif
//------------------------------------------------------------------------------


//------------------------------------------------------------------------------
/******************************************************************************************/











 
/******************************************************************************************
 *
 *  WORK WITH DYNAMIC TIMERS
 *
 ******************************************************************************************/


#ifdef OS_ENABLE_DTIMERS

#if   OS_DTIMER_SIZE == 1
    #define OS_INC_DTIMER()                             \
        {                                               \
            /* Now W = fsr */                           \
            asm("   incf    __fsr, f    ");             \
            asm("   incf    __fsr, f    ");             \
            asm("   bcf     __status, 2 ");             \
            asm("   incf    __indf, f   ");             \
            asm("   movwf   __fsr       ");             \
            if (_status & 4) _indf |= 1;                \
        }
#elif OS_DTIMER_SIZE == 2
    #define OS_INC_DTIMER()                             \
        {                                               \
            asm("   bcf     __status, 0 ");             \
            /* Now W = fsr */                           \
            asm("   incf    __fsr, f    ");             \
            asm("   incf    __fsr, f    ");             \
            asm("   incfsz  __indf, f   ");             \
            asm("   goto    $ + 5       ");             \
            asm("   incf    __fsr, f    ");             \
            asm("   incfsz  __indf, f   ");             \
            asm("   goto    $ + 2       ");             \
            asm("   bsf     __status, 0 ");             \
            asm("   movwf   __fsr       ");             \
            if (_status & 1) _indf |= 1;                \
        }
#elif OS_DTIMER_SIZE == 4
    #define OS_INC_DTIMER()                             \
        {                                               \
            asm("   bcf     __status, 0 ");             \
            /* Now W = fsr */                           \
            asm("   incf    __fsr, f    ");             \
            asm("   incf    __fsr, f    ");             \
            asm("   incfsz  __indf, f   ");             \
            asm("   goto    $ + 11      ");             \
            asm("   incf    __fsr, f    ");             \
            asm("   incfsz  __indf, f   ");             \
            asm("   goto    $ + 8       ");             \
            asm("   incf    __fsr, f    ");             \
            asm("   incfsz  __indf, f   ");             \
            asm("   goto    $ + 5       ");             \
            asm("   incf    __fsr, f    ");             \
            asm("   incfsz  __indf, f   ");             \
            asm("   goto    $ + 2       ");             \
            asm("   bsf     __status, 0 ");             \
            asm("   movwf   __fsr       ");             \
            if (_status & 1) _indf |= 1;                \
        }
#endif


#define __OS_DTimersWork()                                  \
    {                                                       \
        _fsr = (_FSR_TYPE) &_OS_DTimers;                    \
        /* Avoid to use CheckIndfReady because of FSR */    \
        /* can be cleared                             */    \
        while (_indf & 8) /* bEnable */                     \
        {                                                   \
            _fsr++;                                         \
            _fsr = _indf;                                   \
            if (!(_indf & 4)) continue; /* Run      */      \
            OS_INC_DTIMER();                                \
        }                                                   \
    }


#endif  // OS_ENABLE_DTIMER




/******************************************************************************************
 *
 *
 *
 ******************************************************************************************/


#endif
